// 内核态陷阱向量：保存通用寄存器、构建trapframe、调用 C 处理、恢复后 sret
.extern kernel_trapframe_ptr
.section .text
.align 4
.globl kernelvec
kernelvec:
  // 为保存寄存器预留空间（trapframe结构大小）
  // trapframe包含：4个CSR + 28个通用寄存器 = 32个uint64 = 256字节
  addi sp, sp, -256

  // 先保存t0和t1，因为我们需要用它们来保存CSR
  sd t0, 64(sp)     // 临时保存t0
  sd t1, 72(sp)     // 临时保存t1

  // 保存CSR寄存器到栈（trapframe的前4个字段）
  csrr t0, sepc
  sd t0, 0(sp)      // sepc
  csrr t0, scause
  sd t0, 8(sp)     // scause
  csrr t0, stval
  sd t0, 16(sp)    // stval
  csrr t0, sstatus
  sd t0, 24(sp)    // sstatus

  // 恢复t0和t1
  ld t0, 64(sp)
  ld t1, 72(sp)

  // 保存通用寄存器到栈（按trapframe结构顺序）
  sd ra,   32(sp)   // ra
  addi t1, sp, 256  // 保存前的sp值
  sd t1,   40(sp)   // sp
  sd gp,   48(sp)   // gp
  sd tp,   56(sp)   // tp
  sd t0,   64(sp)   // t0
  sd t1,   72(sp)   // t1 (注意：t1现在保存的是旧sp)
  sd t2,   80(sp)   // t2
  sd s0,   88(sp)   // s0
  sd s1,   96(sp)   // s1
  sd a0,  104(sp)   // a0
  sd a1,  112(sp)   // a1
  sd a2,  120(sp)   // a2
  sd a3,  128(sp)   // a3
  sd a4,  136(sp)   // a4
  sd a5,  144(sp)   // a5
  sd a6,  152(sp)   // a6
  sd a7,  160(sp)   // a7
  sd s2,  168(sp)   // s2
  sd s3,  176(sp)   // s3
  sd s4,  184(sp)   // s4
  sd s5,  192(sp)   // s5
  sd s6,  200(sp)   // s6
  sd s7,  208(sp)   // s7
  sd s8,  216(sp)   // s8
  sd s9,  224(sp)   // s9
  sd s10, 232(sp)   // s10
  sd s11, 240(sp)   // s11
  sd t3,  248(sp)   // t3
  sd t4,  256(sp)   // t4
  sd t5,  264(sp)   // t5
  sd t6,  272(sp)   // t6

    // 设置全局变量
  la t0, kernel_trapframe_ptr
  sd sp, 0(t0)

  // 将栈指针作为trapframe指针传递给kerneltrap
  // 使用a0传递参数（RISC-V调用约定）
  mv a0, sp
  call kerneltrap

  // 清除全局变量
  la t0, kernel_trapframe_ptr
  sd zero, 0(t0)

  // 先读取保存的sp值到临时寄存器（在恢复栈之前）
  // 使用t6作为临时寄存器（t6是最后一个恢复的）
  ld t6, 40(sp)     // 读取保存的sp值到t6

  // 恢复CSR寄存器
  ld t0, 0(sp)      // sepc
  csrw sepc, t0
  ld t0, 24(sp)    // sstatus
  csrw sstatus, t0

  // 恢复通用寄存器（sp除外，使用t6保存的sp值）
  ld ra,   32(sp)
  ld gp,   48(sp)
  ld tp,   56(sp)
  ld t0,   64(sp)
  ld t1,   72(sp)
  ld t2,   80(sp)
  ld s0,   88(sp)
  ld s1,   96(sp)
  ld a0,  104(sp)
  ld a1,  112(sp)
  ld a2,  120(sp)
  ld a3,  128(sp)
  ld a4,  136(sp)
  ld a5,  144(sp)
  ld a6,  152(sp)
  ld a7,  160(sp)
  ld s2,  168(sp)
  ld s3,  176(sp)
  ld s4,  184(sp)
  ld s5,  192(sp)
  ld s6,  200(sp)
  ld s7,  208(sp)
  ld s8,  216(sp)
  ld s9,  224(sp)
  ld s10, 232(sp)
  ld s11, 240(sp)
  ld t3,  248(sp)
  ld t4,  256(sp)
  ld t5,  264(sp)
  // t6已经在上面读取了sp值，跳过

  // 恢复栈指针（使用之前读取的值）
  addi sp, sp, 256  // 先恢复栈到保存前的位置
  mv sp, t6         // 将保存的sp值写回sp

  // t6是临时寄存器，不需要恢复原始值（caller-saved）

  sret